package com.beiding.config;

import com.beiding.timeout.bean.DelayTaskExecutor;
import com.beiding.timeout.bean.DelayTaskListener;
import com.beiding.timeout.bean.DelayTaskPersistence;
import com.beiding.timeout.bean.TimeShaft;
import com.beiding.timeout.dao.*;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.List;


@Configuration
public class Config {

    @Bean
    public StringRedisSerializer stringRedisSerializer() {
        return new StringRedisSerializer();
    }

    @Bean
    public JdkSerializationRedisSerializer jdkSerializationRedisSerializer() {
        return new JdkSerializationRedisSerializer();
    }


    @Bean
    public TimeShaftDao<String> timeShaftDao(TasksMap<String> tasksMap, TaskIndexMap taskIndexMap, TimeShaftDescription timeShaftDescription, TaskMarkerSortedSet taskMarkerSortedSet) {
        return new TimeShaftDaoImpl<>(timeShaftDescription, taskMarkerSortedSet, taskIndexMap, tasksMap);
    }

    @Bean
    public DelayTaskListener<String> listener() {
        return new DelayTaskListener<String>("test") {
            @Override
            public void run(String payload) {

                System.out.println("负载为:" + payload);

            }

            @Override
            public void onError(DelayTaskPersistence<String> persistence) {

                System.out.println("抛异常");

            }
        };
    }


    @Bean
    public DelayTaskExecutor<String> delayTaskExecutor(List<DelayTaskListener<String>> list) {
        DelayTaskExecutor<String> executor = new DelayTaskExecutor<>();
        executor.addListeners(list);
        return executor;
    }

    @Bean
    public TimeShaft<String> timeShaft(TimeShaftDao<String> timeShaftDao, RabbitTemplate rabbitTemplate) {
        return new TimeShaft<>(timeShaftDao, 1000, 20 * 1000, occurTime -> {
            //进行任务派发
            rabbitTemplate.convertAndSend("test.test", occurTime);
        });

    }

    @Bean
    public Queue ds() {

        return new Queue("test.test");

    }

    @Bean
    public Queue exe() {

        return new Queue("test.exe");

    }

    private TimeShaftDao<String> timeShaftDao;

    @Autowired
    public void setTimeShaftDao(TimeShaftDao<String> timeShaftDao) {
        this.timeShaftDao = timeShaftDao;
    }

    private DelayTaskExecutor<String> executor;

    @Autowired
    public void setExecutor(DelayTaskExecutor<String> executor) {
        this.executor = executor;
    }

    private RabbitTemplate rabbitTemplate;

    @Autowired
    public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    @RabbitListener(queues = "test.test")
    public void distribute(Long time) {

        timeShaftDao.getTasks(time).forEach(stringDelayTaskPersistence -> {

            rabbitTemplate.convertAndSend("test.exe", stringDelayTaskPersistence);
        });

    }


    public static void main(String[] args) {

        String s = "edf";


        System.out.println(s.hashCode());

    }


    @RabbitListener(queues = "test.exe")
    public void exe(DelayTaskPersistence<String> stringDelayTaskPersistence) {

        if (executor.execute(stringDelayTaskPersistence)) {
            timeShaftDao.remove(stringDelayTaskPersistence.getId());

        }

    }


    @Component
    public static class LongRedisSerializer implements RedisSerializer<Long> {

        @Override
        public byte[] serialize(Long o) throws SerializationException {
            long temp = o;
            byte[] b = new byte[8];
            for (int i = 0; i < b.length; i++) {
                b[i] = (byte) (temp & 0xff);
                temp = temp >> 8;
            }
            return b;
        }

        @Override
        public Long deserialize(byte[] b) throws SerializationException {
            long s = 0;
            for (int i = 0; i < 8; i++) {
                long v = b[i] & 0xff;
                v <<= (8 * i);
                s = s | v;
            }
            return s;

        }

    }


}
